package com.numbfish.ch81_ex02_selenium_official_start.test;

import cn.hutool.core.io.file.FileReader;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.numbfish.ch81_ex02_selenium_official_start.DriverBase;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

// 继承后不需要自己手动关闭浏览器
public class Oauth2SeleniumTest2 extends DriverBase {
    private RemoteWebDriver driver;

    @BeforeEach
    public void setup() throws MalformedURLException {
        driver = getDriver();
    }

    @Test
    void testBing(){
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        driver.get("http://localhost:9000/blank");
        assertThat(isjQueryLoaded()).isEqualTo(false);
        String bootstrap5Url ="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css";
        injectScript("https://code.jquery.com/jquery-latest.min.js");
        injectLink(bootstrap5Url);
        wait.until(jQueryHasLoaded());
        assertThat(isjQueryLoaded()).isEqualTo(true);
        // 渲染html元素
        render();
        addCss();
        System.out.println("rendered");
    }

    @Test
    void testGetToken() throws MalformedURLException, InterruptedException {
        String authorizationCode = getAuthorizationCode();
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        driver.get("http://127.0.0.1:9000/login");
        assertThat(isjQueryLoaded()).isEqualTo(false);
        injectScript("https://code.jquery.com/jquery-latest.min.js");
        wait.until(jQueryHasLoaded());
        assertThat(isjQueryLoaded()).isEqualTo(true);
        // 渲染html元素
        render();
        // 添加样式
        addCss();
        // 绑定click事件
        bindEvent();
        WebElement authorization_code_input = driver.findElement(By.id("show-code"));
        setElementText("#show-code",authorizationCode);
        wait.until((ExpectedCondition<Boolean>) d -> {
            return !d.findElement(By.id("show-code")).getText().equals("");
        });
        WebElement authorization_code_btn = driver.findElement(By.id("get-token-btn"));
        //authorization_code_btn.click();
        Actions actions = new Actions(driver);
        actions.moveToElement(authorization_code_btn).click().perform();
        WebElement tokenElement = driver.findElement(By.id("show-token"));
        //System.out.println(tokenElement);
        wait.until((ExpectedCondition<Boolean>) d ->tokenElement.getText().length()>1);
        String text = tokenElement.getText();
        JSONObject jsonObject = JSONObject.parseObject(text);
        // 格式化json
        String formatStr = JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        System.out.println(formatStr);
        Thread.sleep(30000);
    }
    @Test
    public void outputAuthorizationCode(){
        getAuthorizationCode();
    }
    private String getAuthorizationCode() {
        String REDIRECT_URI = "http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc";
        String GET_CODE_REQUEST = "http://localhost:9000" + UriComponentsBuilder
                .fromPath("/oauth2/authorize") // 由OAuth2ClientAuthenticationFilter处理
                .queryParam("response_type", "code")
                .queryParam("client_id", "messaging-client")
                .queryParam("scope", "openid")
                .queryParam("redirect_uri", REDIRECT_URI)
                .queryParam("code_challenge", "PQMokzLSTbIoTutjAge9SFzApG0ifHQIy-dGc91_ggE")
                .queryParam("code_challenge_method", "S256")
                .toUriString();
        // driver.manage().window().maximize();  // 最大化窗口
        // int a = 10/0; // @AfterAll即使出现异常也会关闭浏览器
        //System.out.println(GET_CODE_REQUEST);
        driver.get(GET_CODE_REQUEST);
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        //System.out.println("请求等待前-login-当前打开页面url是： " + driver.getCurrentUrl());
        wait.until((ExpectedCondition<Boolean>) d -> d.getCurrentUrl().toLowerCase().contains("login"));
        //System.out.println("请求等待后-login-当前打开页面url是： " + driver.getCurrentUrl());
        WebElement username = driver.findElement(By.id("username"));
        username.sendKeys("user");
        WebElement password = driver.findElement(By.id("password"));
        password.sendKeys("password");
        Actions actions = new Actions(driver);
        WebElement element = driver.findElement(By.cssSelector("button[type='submit']"));
        // 交互方式点击登录
        actions.moveToElement(element).click().perform();
        //System.out.println("等待前-点击登录-当前打开页面的标题是： " + driver.getCurrentUrl());
        wait.until((ExpectedCondition<Boolean>) d -> d.getCurrentUrl().toLowerCase().contains("code="));
        //System.out.println("等待后-点击登录-当前打开页面的标题是： " + driver.getCurrentUrl());
        Map<String, String> map = getParameter(driver.getCurrentUrl());
        String codeGot = map.get("code");
        System.out.println("-------------------code-------------------");
        System.out.println("code == " + codeGot);
        System.out.println("-------------------code-------------------");
        return codeGot;
    }

    public static Map<String, String> getParameter(String url) {
        Map<String, String> map = new HashMap<String, String>();
        try {
            final String charset = "utf-8";
            url = URLDecoder.decode(url, charset);
            if (url.indexOf('?') != -1) {
                final String contents = url.substring(url.indexOf('?') + 1);
                String[] keyValues = contents.split("&");
                for (int i = 0; i < keyValues.length; i++) {
                    if (keyValues[i].contains("=")) {
                        String key = keyValues[i].substring(0, keyValues[i].indexOf("="));
                        String value = keyValues[i].substring(keyValues[i].indexOf("=") + 1);
                        map.put(key, value);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }
    public void setElementText(String selector,String content){
        String script =  "$("+"'"+selector+"'"+").text("+"'"+content+"'"+")";
        driver.executeScript(script);
    }

    private void injectScript(String scriptURL) {
        driver.executeScript("function injectScript(url) {\n" +
                        "    var script = document.createElement('script');\n" +
                        "    script.src = url;\n" +
                        "    var head = document.getElementsByTagName('head')[0];\n" +
                        "    head.appendChild(script);\n" +
                        "}\n" +
                        "\n" +
                        "var scriptURL = arguments[0];\n" +
                        "injectScript(scriptURL);"
                , scriptURL);
    }

    private void injectLink(String linkURL) {
        driver.executeScript("function injectLink(url) {\n" +
                        "   var linkElement = document.createElement('link'); \n" +
                        "   linkElement.setAttribute('rel', 'stylesheet');\n" +
                        "   linkElement.setAttribute('href', url);\n" +
                        "   var head = document.getElementsByTagName('head')[0];\n" +
                        "   head.appendChild(linkElement);\n" +
                        "}\n" +
                        "\n" +
                        "var linkURL = arguments[0];\n" +
                        "injectLink(linkURL);"
                , linkURL);
    }



    private Boolean isjQueryLoaded() {
        return (Boolean) driver.executeScript("return typeof jQuery != 'undefined';");
    }

    // private Boolean createDiv(){return (Boolean) driver.executeScript("return $('body').append('<p>hello jquery</p>');");}
    private void render() {
        String script =readStringFromJsFile("js/renderElement.js");
        driver.executeScript(script);
    }
    private void bindEvent() {
        String script = readStringFromJsFile("js/bindEvent.js");
        driver.executeScript(script);
    }

    private void addCss()  {
        String script = CssParserUtils.generateJqueryCssFromFile("js/renderCss.css");
        //System.out.println(script);
        driver.executeScript(script);
    }
    private static ExpectedCondition<Boolean> jQueryHasLoaded() {
        return webDriver -> {
            JavascriptExecutor js = (JavascriptExecutor) webDriver;
            return Boolean.valueOf(js.executeScript("return typeof jQuery != 'undefined';").toString());
        };
    }

    static String readStringFromJsFile(String path){
        //默认UTF-8编码，可以在构造中传入第二个参数做为编码
        FileReader fileReader = new FileReader(path);
        String result = fileReader.readString();
        return result;
    }
}
